#pragma once

#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>
//后面还要改吧改吧

template <typename T>
class BlockQueue
{
private:
   bool IsFull()
   {
      return _block_queue.size() == _cap;
   }

   bool IsEmpty()
   {
      return _block_queue.empty();
   }

public:
   BlockQueue(int cap) : _cap(cap)
   {
      _product_wait_num = 0;
      _consume_wait_num = 0;
      pthread_mutex_init(&_mutex, nullptr);
      pthread_cond_init(&_product_cond, nullptr);
      pthread_cond_init(&_consume_cond, nullptr);
   }

   ~BlockQueue()
   {
      pthread_mutex_destroy(&_mutex);
      pthread_cond_destroy(&_product_cond);
      pthread_cond_destroy(&_consume_cond);
   }

   // 生产者接口
   void Enqueue(T &item)
   {
      // 要进入临界区先锁上
      pthread_mutex_lock(&_mutex);
      // 要多次判满
      while (IsFull())
      {
         _product_wait_num++;
         pthread_cond_wait(&_product_cond, &_mutex);
         _product_wait_num--;
      }

      // 进行生产
      _block_queue.push(item);

      // 通知消费者可以消费了
      if (_consume_wait_num > 0)
         // 一个一个叫
         pthread_cond_signal(&_consume_cond);
      pthread_mutex_unlock(&_mutex);
    
   }

   // 消费者接口
   void Pop(T *out) 
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty()) // 保证代码的健壮性
        {
          
            _consume_wait_num++;
            pthread_cond_wait(&_consume_cond, &_mutex);  // 伪唤醒
          _consume_wait_num--;
        }

        // 进行消费
        *out = _block_queue.front();
        _block_queue.pop();
        // 通知生产者来生产
        if(_product_wait_num > 0)
            pthread_cond_signal(&_product_cond);
        pthread_mutex_unlock(&_mutex);
        
    }

private:
   std::queue<T> _block_queue;
   int _cap;               // 容量
   pthread_mutex_t _mutex; // 保护_block_queue的互斥锁

   pthread_cond_t _product_cond; // 生产者条件变量
   pthread_cond_t _consume_cond; // 消费者条件变量

   int _product_wait_num;
   int _consume_wait_num;
};
